import { Box, Container, Grid, Link, List, ListItem, Paper, Typography } from '@mui/material';
import { FC, useState } from 'react';
import { Link as RouterLink, useLocation, useNavigate } from 'react-router-dom';
import Layout from '../../components/Layout';

const CodeBlock = ({ children }: { children: string }) => (
  <Box
    component="pre"
    sx={{
      backgroundColor: '#f5f5f5',
      padding: 2,
      borderRadius: 1,
      overflowX: 'auto',
      '& code': {
        fontFamily: 'monospace',
      },
    }}
  >
    <code>{children}</code>
  </Box>
);

const JavaScriptAdvanced: FC = () => {
  const location = useLocation();
  const navigate = useNavigate();
  const [selectedTopic, setSelectedTopic] = useState<string>('closure');
  const currentHash = location.hash.slice(1);

  const handleNavigation = (path: string, isMainItem = false) => {
    setSelectedTopic(path);
    if (isMainItem) {
      window.location.hash = path;
    }
  };

  const menuItems = [
    {
      title: '闭包',
      path: 'closure',
      subItems: [
        { title: '什么是闭包', id: 'what-is-closure' },
        { title: '闭包的应用', id: 'closure-applications' },
        { title: '闭包的注意事项', id: 'closure-considerations' },
      ],
    },
    {
      title: '原型与原型链',
      path: 'prototype',
      subItems: [
        { title: '原型对象', id: 'prototype-object' },
        { title: '原型链', id: 'prototype-chain' },
        { title: '继承', id: 'inheritance' },
      ],
    },
    {
      title: '异步编程',
      path: 'async',
      subItems: [
        { title: 'Promise', id: 'promise' },
        { title: 'async/await', id: 'async-await' },
        { title: '异步迭代器', id: 'async-iterators' },
      ],
    },
    {
      title: '事件循环',
      path: 'event-loop',
      subItems: [
        { title: '宏任务与微任务', id: 'macro-micro-tasks' },
        { title: '事件循环机制', id: 'event-loop-mechanism' },
        { title: '实际应用', id: 'practical-applications' },
      ],
    },
    {
      title: '内存管理与垃圾回收',
      path: 'memory',
      subItems: [
        { title: '内存生命周期', id: 'memory-lifecycle' },
        { title: '垃圾回收机制', id: 'garbage-collection' },
        { title: '内存泄漏', id: 'memory-leaks' },
      ],
    },
  ];

  const TableOfContents: React.FC = () => (
    <Box
      sx={{
        position: 'sticky',
        top: 20,
        bgcolor: '#f5f5f5',
        p: 2,
        borderRadius: 1,
      }}
    >
      <Typography variant="h6" gutterBottom>
        目录
      </Typography>
      {menuItems.map(item => (
        <Box key={item.path} sx={{ mb: 2 }}>
          <RouterLink
            to={`#${item.path}`}
            onClick={() => handleNavigation(item.path, true)}
            style={{
              color: '#1976d2',
              textDecoration: 'none',
              fontWeight: selectedTopic === item.path ? 'bold' : 'normal',
            }}
          >
            <Typography>{item.title}</Typography>
          </RouterLink>
          {item.subItems && (
            <Box sx={{ ml: 2, mt: 1 }}>
              {item.subItems.map(subItem => (
                <RouterLink
                  key={subItem.id}
                  to={`#${subItem.id}`}
                  onClick={() => handleNavigation(subItem.id)}
                  style={{
                    display: 'block',
                    color: '#666',
                    textDecoration: 'none',
                    fontSize: '0.9em',
                    marginBottom: '0.5em',
                    fontWeight: selectedTopic === subItem.id ? 'bold' : 'normal',
                  }}
                >
                  <Typography>{subItem.title}</Typography>
                </RouterLink>
              ))}
            </Box>
          )}
        </Box>
      ))}
    </Box>
  );

  const getContent = () => {
    switch (selectedTopic) {
      case 'closure':
        return (
          <Box>
            <Typography variant="h4" gutterBottom id="closure">
              闭包
            </Typography>
            <Typography paragraph>
              闭包是 JavaScript 中最重要的概念之一，它允许函数访问其词法作用域之外的变量。
            </Typography>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="what-is-closure">
                什么是闭包
              </Typography>
              <Typography paragraph>
                闭包是指一个函数可以记住并访问其词法作用域，即使该函数在其词法作用域之外执行。
              </Typography>
              <CodeBlock>{`// 闭包示例
function createCounter() {
  let count = 0;  // 私有变量
  
  return {
    increment() {
      return ++count;
    },
    decrement() {
      return --count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="closure-applications">
                闭包的应用
              </Typography>
              <Typography paragraph>
                闭包在 JavaScript 中有许多实际应用场景，以下是一些常见的用法：
              </Typography>
              <CodeBlock>{`// 1. 数据私有化
function createUser(name) {
  let password = '123456';  // 私有变量
  
  return {
    getName() {
      return name;
    },
    login(pwd) {
      return pwd === password;
    },
    changePassword(oldPwd, newPwd) {
      if (oldPwd === password) {
        password = newPwd;
        return true;
      }
      return false;
    }
  };
}

const user = createUser('张三');
console.log(user.getName());     // 张三
console.log(user.password);      // undefined
console.log(user.login('123456')); // true

// 2. 函数工厂
function multiply(x) {
  return function(y) {
    return x * y;
  };
}

const multiplyByTwo = multiply(2);
const multiplyByThree = multiply(3);

console.log(multiplyByTwo(4));   // 8
console.log(multiplyByThree(4)); // 12

// 3. 模块模式
const calculator = (function() {
  let result = 0;
  
  return {
    add(x) {
      result += x;
      return this;
    },
    subtract(x) {
      result -= x;
      return this;
    },
    getResult() {
      return result;
    }
  };
})();

calculator.add(5).subtract(2);
console.log(calculator.getResult()); // 3`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="closure-considerations">
                闭包的注意事项
              </Typography>
              <Typography paragraph>使用闭包时需要注意以下几点：</Typography>
              <Typography component="ol" sx={{ pl: 3 }}>
                <li>
                  <Typography paragraph>
                    内存占用：闭包会保持对外部变量的引用，可能导致内存无法及时释放。
                  </Typography>
                </li>
                <li>
                  <Typography paragraph>
                    变量共享：多个闭包可能共享同一个外部变量，需要注意变量的作用域和生命周期。
                  </Typography>
                </li>
                <li>
                  <Typography paragraph>
                    性能考虑：过度使用闭包可能影响性能，应该在必要时才使用。
                  </Typography>
                </li>
              </Typography>
              <CodeBlock>{`// 闭包陷阱示例
function createFunctions() {
  const result = [];
  
  // 错误示例
  for (var i = 0; i < 3; i++) {
    result.push(function() {
      console.log(i);
    });
  }
  
  // 正确示例
  for (let i = 0; i < 3; i++) {
    result.push(function() {
      console.log(i);
    });
  }
  
  return result;
}

const functions = createFunctions();
functions[0](); // 使用 var: 3, 使用 let: 0
functions[1](); // 使用 var: 3, 使用 let: 1
functions[2](); // 使用 var: 3, 使用 let: 2

// 内存泄漏示例
function setupHandler() {
  const element = document.getElementById('button');
  let count = 0;
  
  element.addEventListener('click', () => {
    console.log(++count);
  });
}

// 建议的做法：在不需要时移除事件监听器
function setupHandler() {
  const element = document.getElementById('button');
  let count = 0;
  
  const handler = () => {
    console.log(++count);
  };
  
  element.addEventListener('click', handler);
  
  // 提供清理方法
  return () => {
    element.removeEventListener('click', handler);
  };
}`}</CodeBlock>
            </Box>
          </Box>
        );

      case 'prototype':
        return (
          <Box>
            <Typography variant="h4" gutterBottom id="prototype">
              原型与原型链
            </Typography>
            <Typography paragraph>
              原型和原型链是 JavaScript 实现继承的核心机制，理解这个概念对于掌握 JavaScript
              面向对象编程至关重要。
            </Typography>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="prototype-object">
                原型对象
              </Typography>
              <Typography paragraph>
                在 JavaScript 中，每个对象都有一个原型对象，对象从原型继承属性和方法。
                当我们创建一个函数时，JavaScript 会自动为这个函数创建一个 prototype 属性，
                这个属性指向函数的原型对象。
              </Typography>
              <CodeBlock>{`// 构造函数
function Person(name) {
  this.name = name;
}

// 在原型上添加方法
Person.prototype.sayHello = function() {
  console.log(\`你好，我是 \${this.name}\`);
};`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="prototype-chain">
                原型链
              </Typography>
              <Typography paragraph>
                当访问一个对象的属性时，如果这个对象本身没有这个属性，那么它会去它的原型对象中寻找这个属性。
                这个过程会一直持续到找到该属性或到达原型链的末端（null）。
              </Typography>
              <CodeBlock>{`// 原型链示例
const animal = {
  eat: function() {
    console.log('吃东西');
  }
};`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="inheritance">
                继承
              </Typography>
              <Typography paragraph>
                JavaScript 通过原型链实现继承。我们可以使用不同的方式来创建继承关系。
              </Typography>
              <CodeBlock>{`// 类继承（ES6+）
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(\`\${this.name} 发出声音\`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name);
  }
  
  bark() {
    console.log(\`\${this.name} 汪汪汪\`);
  }
}

const dog = new Dog('旺财');
dog.speak(); // 输出：旺财 发出声音
dog.bark();  // 输出：旺财 汪汪汪

// 原型继承（ES5）
function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function() {
  console.log(\`\${this.name} 发出声音\`);
};

function Dog(name) {
  Animal.call(this, name); // 调用父类构造函数
}

// 设置原型链
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function() {
  console.log(\`\${this.name} 汪汪汪\`);
};`}</CodeBlock>
            </Box>
          </Box>
        );

      case 'async':
        return (
          <Box>
            <Typography variant="h4" gutterBottom id="async">
              异步编程
            </Typography>
            <Typography paragraph>
              异步编程是 JavaScript 中处理非阻塞操作的重要概念。 从最早的回调函数，到
              Promise，再到现代的 async/await，异步编程模式不断演进。
            </Typography>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="promise">
                Promise
              </Typography>
              <Typography paragraph>
                Promise 是异步编程的一种解决方案，比传统的回调函数更加优雅。
                它可以将异步操作以同步操作的流程表达出来，避免了回调地狱。
              </Typography>
              <CodeBlock>{`// Promise 基础使用
const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    const random = Math.random();
    if (random > 0.5) {
      resolve('成功：' + random);
    } else {
      reject('失败：' + random);
    }
  }, 1000);
});`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="async-await">
                async/await
              </Typography>
              <Typography paragraph>
                async/await 是 ES2017 引入的特性，它是基于 Promise 的更高层的抽象，
                使异步代码看起来更像同步代码。
              </Typography>
              <CodeBlock>{`// async/await 基础使用
async function fetchUserData(userId) {
  try {
    const response = await fetch(\`https://api.example.com/users/\${userId}\`);
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('获取用户数据失败：', error);
    throw error;
  }
}`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="async-iterators">
                异步迭代器
              </Typography>
              <Typography paragraph>
                异步迭代器允许我们异步地遍历数据，它在处理流数据或大量数据时特别有用。
              </Typography>
              <CodeBlock>{`// 异步迭代器示例
async function* createAsyncIterator() {
  for (let i = 0; i < 5; i++) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield i;
  }
}

// 使用 for await...of
async function useAsyncIterator() {
  const iterator = createAsyncIterator();
  for await (const value of iterator) {
    console.log(value);
  }
}

// 自定义异步迭代器
class AsyncNumberGenerator {
  constructor(start = 0, end = Infinity, interval = 1000) {
    this.start = start;
    this.end = end;
    this.interval = interval;
  }

  [Symbol.asyncIterator]() {
    let count = this.start;
    return {
      next: async () => {
        if (count <= this.end) {
          await new Promise(resolve => setTimeout(resolve, this.interval));
          return { value: count++, done: false };
        }
        return { done: true };
      }
    };
  }
}

// 使用自定义异步迭代器
async function useCustomIterator() {
  const numbers = new AsyncNumberGenerator(1, 5, 1000);
  for await (const num of numbers) {
    console.log(num);
  }
}`}</CodeBlock>
            </Box>
          </Box>
        );

      case 'event-loop':
        return (
          <Box>
            <Typography variant="h4" gutterBottom id="event-loop">
              事件循环
            </Typography>
            <Typography paragraph>
              事件循环是 JavaScript 实现异步编程的核心机制， 它解释了 JavaScript
              引擎如何处理多个任务的执行顺序。
            </Typography>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="macro-micro-tasks">
                宏任务与微任务
              </Typography>
              <Typography paragraph>
                JavaScript 中的任务可以分为宏任务（MacroTask）和微任务（MicroTask）。
                微任务优先级高于宏任务。
              </Typography>
              <CodeBlock>
                {`// 宏任务示例
setTimeout(() => console.log('setTimeout 1'), 0);
setTimeout(() => console.log('setTimeout 2'), 0);`}
              </CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="event-loop-mechanism">
                事件循环机制
              </Typography>
              <Typography paragraph>
                事件循环包含多个关键组件：调用栈（Call Stack）、任务队列（Task Queue）、
                微任务队列（Microtask Queue）。
              </Typography>
              <CodeBlock>
                {`// 调用栈示例
function foo() {
  console.log('foo');
  throw new Error('出错了！');
}`}
              </CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="practical-applications">
                实际应用
              </Typography>
              <Typography paragraph>
                理解事件循环对于编写高性能的 JavaScript 代码至关重要，
                尤其是在处理复杂的异步操作时。
              </Typography>
              <CodeBlock>
                {`// 优化性能示例
async function optimizedOperation() {
  // 将耗时操作放在下一个事件循环中执行
  await Promise.resolve();
}`}
              </CodeBlock>
            </Box>
          </Box>
        );

      case 'memory':
        return (
          <Box>
            <Typography variant="h4" gutterBottom id="memory">
              内存管理与垃圾回收
            </Typography>
            <Typography paragraph>
              JavaScript
              是一门具有自动内存管理的语言，但了解其内存管理机制对于编写高性能的应用程序至关重要。
            </Typography>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="memory-lifecycle">
                内存生命周期
              </Typography>
              <Typography paragraph>
                JavaScript 中的内存生命周期包括：分配内存、使用内存和释放内存三个阶段。
              </Typography>
              <CodeBlock>{`// 内存分配示例
// 1. 变量声明
let number = 123;           // 为数字分配内存
let string = "Hello";       // 为字符串分配内存`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="garbage-collection">
                垃圾回收机制
              </Typography>
              <Typography paragraph>
                JavaScript
                使用自动垃圾回收机制来释放不再使用的内存。主要使用标记-清除算法和引用计数算法。
              </Typography>
              <CodeBlock>{`// 标记-清除算法示例
let user = {
  name: "张三",
  age: 25
};

let admin = user;  // 对象现在有两个引用
user = null;       // 对象仍然可以通过 admin 访问

admin = null;      // 现在对象没有引用了，将被垃圾回收

// 循环引用示例
function createCircularReference() {
  let obj1 = {};
  let obj2 = {};
  
  obj1.ref = obj2;  // obj1 引用 obj2
  obj2.ref = obj1;  // obj2 引用 obj1
  
  return "函数执行完毕";
}  // 尽管有循环引用，但函数执行完后这些对象都可以被回收

// WeakMap 和 WeakSet
let weakMap = new WeakMap();
let obj = { data: "some data" };

weakMap.set(obj, "metadata");
obj = null;  // obj 可以被垃圾回收，weakMap 中的对应条目也会被移除`}</CodeBlock>
            </Box>

            <Box component="section" mt={3}>
              <Typography variant="h5" gutterBottom id="memory-leaks">
                内存泄漏
              </Typography>
              <Typography paragraph>
                即使有自动垃圾回收，JavaScript
                应用程序仍然可能发生内存泄漏。以下是一些常见的内存泄漏场景及其解决方案。
              </Typography>
              <CodeBlock>{`// 1. 全局变量
function leak() {
  leakedVariable = "我会泄漏到全局作用域";  // 没有使用 let/const/var
}

// 修复：使用严格模式
'use strict';
function noLeak() {
  let localVariable = "我是局部变量";
}

// 2. 被遗忘的定时器
function setTimer() {
  let heavyObject = { /* 大量数据 */ };
  
  setInterval(() => {
    console.log(heavyObject);
  }, 1000);
}  // heavyObject 永远不会被回收

// 修复：保存定时器ID并在适当时候清除
function setTimerFixed() {
  let heavyObject = { /* 大量数据 */ };
  let timerId = setInterval(() => {
    console.log(heavyObject);
  }, 1000);
  
  // 清理函数
  return function cleanup() {
    clearInterval(timerId);
    heavyObject = null;
  };
}

// 3. 闭包导致的内存泄漏
function addHandler() {
  let element = document.getElementById('button');
  let heavyData = new Array(10000).fill('*');
  
  element.addEventListener('click', () => {
    console.log(heavyData);
  });
}  // heavyData 会一直存在

// 修复：移除事件监听器
function addHandlerFixed() {
  let element = document.getElementById('button');
  let heavyData = new Array(10000).fill('*');
  
  const handler = () => {
    console.log(heavyData);
  };
  
  element.addEventListener('click', handler);
  
  // 提供清理方法
  return function cleanup() {
    element.removeEventListener('click', handler);
    heavyData = null;
  };
}

// 4. DOM 引用
function cacheDOM() {
  let elements = [];
  let element = document.getElementById('item');
  elements.push(element);
  
  document.body.removeChild(element);  // DOM 节点被移除，但仍被 elements 数组引用
}

// 修复：清除 DOM 引用
function cacheDOMFixed() {
  let elements = [];
  let element = document.getElementById('item');
  elements.push(element);
  
  document.body.removeChild(element);
  elements = [];  // 清除引用`}</CodeBlock>
            </Box>
          </Box>
        );

      // 其他 case 分支将在后续添加

      default:
        return (
          <Box>
            <Typography variant="h4" gutterBottom>
              JavaScript进阶教程
            </Typography>
            <Typography variant="body1" paragraph>
              欢迎来到JavaScript进阶教程。在这里，你将深入学习JavaScript的高级概念和特性。
            </Typography>
            <Typography variant="body1" paragraph>
              请从左侧菜单选择要学习的主题，或从右侧目录快速导航到具体内容。
            </Typography>
            <List>
              {menuItems.map(item => (
                <ListItem key={item.path}>
                  <Box>
                    <Typography variant="h6">{item.title}</Typography>
                    <Typography variant="body2" color="text.secondary">
                      {item.subItems.map(sub => sub.title).join('、')}
                    </Typography>
                  </Box>
                </ListItem>
              ))}
            </List>
          </Box>
        );
    }
  };

  return (
    <Layout>
      <Grid container spacing={3} sx={{ maxWidth: '1200px', margin: '0 auto', p: 3 }}>
        <Grid item xs={12} md={9}>
          {getContent()}
        </Grid>
        <Grid item xs={12} md={3}>
          <TableOfContents />
        </Grid>
      </Grid>
    </Layout>
  );
};

export default JavaScriptAdvanced;
